<?php
//微信支付V3版本 TP5 TP6版本
namespace app\home\controller;

use think\facade\Db;
use think\App;
use app\BaseController;
class WxpayV3 extends BaseController
{	
    private $xcx_appid = '';//小程序appid
    private $xcx_appsecret = '';//小程序appsecret
	
	private $gzh_appid = '';//公众号appid
    private $gzh_appsecret = '';//公众号appsecret
	private $mch_private_key = './wxpay/cert/apiclient_key.pem';//证书私钥路径
	//https://myssl.com/cert_decode.html 可上传.cert证书直接获取序列号
	private $serial_no = "132F8119EDF35E196E0A5437EF5B716CE503CA8F";//商户API证书序列号serial_no
    private $request_body = '';//请求报文主体
	
    private $body = '';//支付提示
    private $mch_id = '';//商户号
    private $mch_key = '';//支付秘钥
    private $mck_key_sanxbox = '31ad3f86d51ef27281c0a09fa7f89926';//沙盒签名
    private $ip = '218.60.0.215';
	
	
    private $is_test = true;//是否沙盒测试
	
	public function __construct()
	{
		// $request = Request::instance();
		$xcx = Db::name('wx_xcx')->where('id',1)->find();//小程序配置表
		$this->xcx_appid 	 = $xcx['appid'];
		$this->xcx_appsecret = $xcx['appsecret'];
		$gzh = Db::name('wx_gzh')->where('id',1)->find();//公众号配置表
		$this->gzh_appid 	 = $gzh['appid'];
		$this->gzh_appsecret = $gzh['appsecret'];
		//支付配置
		$this->mch_id 	= Db::name('pay_config')->where(['from'=>'wx','title'=>'wx_mchid'])->value('value');
		$this->mch_key 	= Db::name('pay_config')->where(['from'=>'wx','title'=>'wx_key'])->value('value');
		$this->ip 		= Db::name('pay_config')->where(['from'=>'wx','title'=>'wx_ip'])->value('value');
		$this->body 	= Db::name('pay_config')->where(['from'=>'wx','title'=>'wx_body'])->value('value');

	}
     /**
     * # +========================================================================
     * # | - @name       Native扫码支付(V3文档)
     * # | - @author     weapon 
     * # | - @copyright  2021-01-20
     * # +========================================================================
     */
	public function native_pay($order_id){
		$orderInfo = Db::name('order')->where(['order_id'=>$order_id])->find();
		// ll($orderInfo);die;
		if(empty($orderInfo)){
			return json(['msg'=>'订单异常','status'=>2]);exit;
		}
		$url='https://api.mch.weixin.qq.com/v3/pay/transactions/native';
		$arr=[
			'appid'=>$this->gzh_appid,
			'mchid'=>$this->mch_id,
			'description'=>$this->body,
			// 'out_trade_no'=>$orderInfo['order_no'],
			'out_trade_no'=>date('YmdHis',time()).'3333',
			'notify_url'=>'http://www.lyhsnd.cn/admin.php/Wxpay/payNotify',
			'amount'=>array(
				'total'=>intval($orderInfo['order_amount'] * 100),
				'currency'=>"CNY"
			)
		];
        // ll($arr);die;
        $authorization_code = $this->getNoncestr();
        // echo $authorization_code;die;
        $result = $this->execute($url,$arr,'POST');
        if($result['httpcode']==200){
        	$body = json_decode($result['data'],true);
        	// ll($body['code_url']);exit;
        	return ['status'=>200,'code_url'=>$body['code_url']];exit;
        }else{
        	return ['status'=>400,'msg'=>'请求失败'];exit;
        }
        // ll($result);die;
        // $data   = json_decode($result['data'],true);
        // return $this -> success($data);
    }
	        
    /**
     * # +========================================================================
     * # | - @name        执行
     * # | - @author     cq <just_leaf@foxmail.com> 
     * # | - @copyright zmtek 2021-01-20
     * # +========================================================================
     */
    
    public function execute($url,$body = null,$http_method = 'POST') {
        # 转化大写
        $http_method = strtoupper($http_method);
        if($http_method == 'POST') {
            $body   = json_encode($body);
        }else{
            $url    = $url . '?' . http_build_query($body); 
            $body   = null;
        }
        # 分割符号
        $sign       = $this -> getV3Sign($url,$http_method,$body);
        // echo $sign;die;
        $header[]   = 'User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36';
        $header[]   = 'Accept: application/json';
        $header[]   = 'Content-Type: application/json;';
        $header[]   = 'Authorization: WECHATPAY2-SHA256-RSA2048 '.$sign;
        // ll($body);die;
        $exc        = $this -> Curl($url,$body,$http_method,$header);
        // ll($exc);die;
        return $exc;
    }
    
    /**
     * # +========================================================================
     * # | - @name        请求
     * # | - @author     cq <just_leaf@foxmail.com> 
     * # | - @copyright zmtek 2021-01-20
     * # +========================================================================
     */
    public function Curl($url, $data, $http_method,$header = array(), $timeout = 30)
    {
        $opts = array(
            CURLOPT_TIMEOUT        => 30,
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_HTTPHEADER     => $header,
            CURLOPT_URL            => $url,
            CURLOPT_HEADER         => 1 ,
        );
        
        # 根据请求类型设置特定参数
        if($http_method == 'POST') {
            
            # 判断是否传输文件
            $opts[CURLOPT_POST] = 1;
            $opts[CURLOPT_POSTFIELDS] = $data;
        }
                
        # 初始化并执行curl请求
        $ch         = curl_init();
        curl_setopt_array($ch, $opts);
        
        $data       = curl_exec($ch);
        $error      = curl_error($ch);
        $httpCode   = curl_getinfo($ch,CURLINFO_HTTP_CODE); 
        curl_close($ch);
        if($error) throw new Exception('请求发生错误：' . $error);
        list($headers, $body) = explode("\r\n\r\n", $data, 2);
        
        $result['data']     = $body;
        $result['httpcode'] = $httpCode;
        $result['headers']  = explode("\r\n", $headers);
        return  $result;
    }
    
    /**
     * # +========================================================================
     * # | - @name        签名
     * # | - @author     cq <just_leaf@foxmail.com> 
     * # | - @copyright zmtek 2021-01-20
     * # +========================================================================
     */
    public function getV3Sign($url,$http_method,$body) {
        # 商户号
        $merchant_id    = $this->mch_id;
        # 随机字符串
        $nonce          = strtoupper($this -> getNoncestr());
        # 商户序列号
        $serial_no      = $this->serial_no;
        # 时间搓
        $timestamp      = time();
        # url
        $url_parts      = parse_url($url);
        # 获取绝对路径
        $canonical_url  = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        # 密钥key
        $private_key    = $this -> getPrivateKey($this->mch_private_key);
        # 拼接参数
        $message        = 
        $http_method."\n".
        $canonical_url."\n".
        $timestamp."\n".
        $nonce."\n".
        $body."\n";
        
        # 获取签名             
        openssl_sign($message, $raw_sign, $private_key, 'sha256WithRSAEncryption');
        $sign   = base64_encode($raw_sign);
        
        $token  = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
        $merchant_id, $nonce, $timestamp, $serial_no, $sign);
        return $token;
    }

    /**
     * # +========================================================================
     * # | - @name        获取私钥
     * # | - @author     cq <just_leaf@foxmail.com> 
     * # | - @copyright zmtek 2019-12-26
     * # +========================================================================
     */
    public function getPrivateKey($filepath) {
        return openssl_get_privatekey(file_get_contents($filepath));
    }
    
    /**
     * # +========================================================================
     * # | - @name        获取随机数
     * # | - @author     cq <just_leaf@foxmail.com> 
     * # | - @copyright zmtek 2021-01-20
     * # +========================================================================
     */
    public function getNoncestr($length = 32) {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str ="";
        for ( $i = 0; $i < $length; $i++ )  {  
            $str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);  
        }  
        return $str;
    }
}